import { Injectable, Logger } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository, DataSource, In } from "typeorm";
import { CharacterTrainingEntity } from "../entities/character-training.entity";
import { CharacterEntity } from "../entities/character.entity";
import { CharacterResourcesEntity } from "../entities/character-resources.entity";
import { CharacterAttributeService } from "./character-attribute.service";
import { CharacterService } from "./character.service";
import { SystemMessageService } from "./system-message.service";
// (已在顶部导入 InjectRepository, Repository)
import { LevelExperienceEntity } from "../entities/level-experience.entity";

@Injectable()
export class CharacterTrainingService {
  private readonly logger = new Logger(CharacterTrainingService.name);

  constructor(
    @InjectRepository(LevelExperienceEntity)
    private readonly levelExpRepository: Repository<LevelExperienceEntity>,
    @InjectRepository(CharacterTrainingEntity)
    private readonly characterTrainingRepository: Repository<CharacterTrainingEntity>,
    @InjectRepository(CharacterEntity)
    private readonly characterRepository: Repository<CharacterEntity>,
    @InjectRepository(CharacterResourcesEntity)
    private readonly characterResourcesRepository: Repository<CharacterResourcesEntity>,
    private readonly dataSource: DataSource,
    private readonly characterAttributeService: CharacterAttributeService,
    private readonly characterService: CharacterService,
    private readonly systemMessageService: SystemMessageService
  ) {}

  /**
   * 计算训练获得经验（按等级、小时数）
   * 规则：训练 h 小时，总经验 = 每小时经验 × h × (1 + h%)
   */
  private async computeTrainingExp(
    level: number,
    hours: number
  ): Promise<number> {
    if (!hours || hours <= 0) return 0;
    const multiplier = this.getTrainingMultiplier(level);

    // 使用 level_experience 表：优先 standard_exp_per_fight，否则按 BASELINE_FIGHTS 回退
    const levelRow = await this.levelExpRepository.findOne({
      where: { level },
    });
    const nextNeed =
      levelRow && Number((levelRow as any).experience) > 0
        ? Number((levelRow as any).experience)
        : 1000;

    const configuredPerFight =
      levelRow && (levelRow as any).standard_exp_per_fight
        ? Number((levelRow as any).standard_exp_per_fight)
        : 0;

    const baselineFightsToLevelUp = Number(process.env.BASELINE_FIGHTS || 1000);
    const fallbackPerFight = Math.max(
      1,
      Math.floor(nextNeed / baselineFightsToLevelUp)
    );

    const expPerFight =
      configuredPerFight > 0 ? configuredPerFight : fallbackPerFight;
    const expPerHour = expPerFight * multiplier;
    const total = expPerHour * hours * (1 + 0.01 * hours);
    return Math.floor(total);
  }

  /**
   * 汇总训练中/已完成角色列表（供1204/1205扩展返回使用）
   */
  private async buildTrainingLists(): Promise<{
    trainingList: Array<{
      id: number;
      name: string;
      hours: number;
      endTime: string | null;
    }>;
    completedList: Array<{
      id: number;
      name: string;
      hours: number;
      endTime: string | null;
    }>;
  }> {
    const trainingRecords = await this.characterTrainingRepository.find({
      where: {},
      order: { updated_at: "DESC" as any },
    });

    const characterIds = Array.from(
      new Set(trainingRecords.map((r) => r.characterId))
    );
    const characters = characterIds.length
      ? await this.characterRepository.findBy({ id: In(characterIds) })
      : [];
    const idToName = new Map<number, string>();
    characters.forEach((c) => idToName.set(c.id, c.name));

    const trainingList: Array<{
      id: number;
      name: string;
      hours: number;
      endTime: string | null;
    }> = [];
    const completedList: Array<{
      id: number;
      name: string;
      hours: number;
      endTime: string | null;
    }> = [];

    for (const r of trainingRecords) {
      const item = {
        id: r.characterId,
        name: idToName.get(r.characterId) || `角色${r.characterId}`,
        hours: r.trainingHours || 0,
        endTime: r.trainingEndTime ? r.trainingEndTime.toISOString() : null,
      };
      if (r.isTraining || r.trainingStatus === 1) {
        trainingList.push(item);
      } else if (r.trainingStatus === 2) {
        completedList.push(item);
      }
    }

    return { trainingList, completedList };
  }

  /**
   * 获取训练经验倍率
   * 根据等级确定训练经验倍率
   */
  private getTrainingMultiplier(level: number): number {
    if (level >= 1 && level <= 40) {
      return 150; // 1-40级：150倍
    } else if (level >= 41 && level <= 70) {
      return 200; // 41-70级：200倍
    } else if (level >= 71 && level <= 160) {
      return 300; // 71-160级：300倍
    }
    return 150; // 默认150倍
  }

  /**
   * 计算训练费用
   * 根据等级计算每小时训练费用
   */
  private calculateTrainingCost(level: number): number {
    if (level >= 1 && level <= 40) {
      return 60;
    } else if (level >= 41 && level <= 70) {
      return 80;
    } else if (level >= 71 && level <= 160) {
      return 100;
    }
    return 60;
  }

  /**
   * 获取训练信息查询 (1204)
   */
  async getTrainingInfo(characterId: number, type: number = 1): Promise<any> {
    try {
      const character = await this.characterRepository.findOne({
        where: { id: characterId },
      });

      if (!character) {
        return {
          act_id: 1204,
          code: -1,
          msg: "角色不存在",
          list: [],
        };
      }

      // 获取24小时内的训练记录
      const now = new Date();
      const since = new Date(now.getTime() - 24 * 60 * 60 * 1000);
      const trainingRecords = await this.characterTrainingRepository.find({
        where: {},
        order: { updated_at: "DESC" as any },
      });

      // 组装角色名映射
      const characterIds = Array.from(
        new Set(trainingRecords.map((r) => r.characterId))
      );
      const characters = characterIds.length
        ? await this.characterRepository.findBy({ id: In(characterIds) })
        : [];
      const idToName = new Map<number, string>();
      characters.forEach((c) => idToName.set(c.id, c.name));

      const getRefTime = (r: any): Date | null => {
        return (
          (r.lastTrainingTime && new Date(r.lastTrainingTime)) ||
          (r.trainingEndTime && new Date(r.trainingEndTime)) ||
          (r.trainingStartTime && new Date(r.trainingStartTime)) ||
          (r.updated_at && new Date(r.updated_at)) ||
          null
        );
      };

      const trainingList: Array<{
        id: number;
        name: string;
        hours: number;
        endTime: string | null;
      }> = [];
      const completedList: Array<{
        id: number;
        name: string;
        hours: number;
        endTime: string | null;
      }> = [];

      for (const r of trainingRecords) {
        const ref = getRefTime(r);
        if (!ref || ref < since) continue; // 仅保留24小时内
        const item = {
          id: r.characterId,
          name: idToName.get(r.characterId) || `角色${r.characterId}`,
          hours: r.trainingHours || 0,
          endTime: r.trainingEndTime ? r.trainingEndTime.toISOString() : null,
        };
        if (r.isTraining) {
          trainingList.push(item);
        } else if (r.trainingStatus === 2) {
          completedList.push(item);
        }
      }

      const list = Number(type) === 2 ? completedList : trainingList;

      return {
        act_id: 1204,
        code: 0,
        list,
        type,
      };
    } catch (error: any) {
      this.logger.error(`获取训练信息失败: characterId=${characterId}`, error);
      return {
        act_id: 1204,
        code: -1,
        msg: error.message || "获取训练信息失败",
        list: [],
      };
    }
  }

  /**
   * 获取训练详情 (1205)
   */
  async getTrainingDetails(characterId: number): Promise<any> {
    try {
      const character = await this.characterRepository.findOne({
        where: { id: characterId },
      });

      if (!character) {
        return {
          act_id: 1205,
          code: -1,
          msg: "角色不存在",
        };
      }

      const resources = await this.characterResourcesRepository.findOne({
        where: { characterId },
      });

      if (!resources) {
        return {
          act_id: 1205,
          code: -1,
          msg: "角色资源不存在",
        };
      }

      // 获取训练状态
      const trainingRecord = await this.characterTrainingRepository.findOne({
        where: { characterId },
      });

      const level = character.lvl;
      const trainingCost = this.calculateTrainingCost(level);
      const multiplier = this.getTrainingMultiplier(level);

      let k = "0"; // 默认未训练状态
      let v = `您现在有${resources.gold}金，当前${level}级训练费用为每小时${trainingCost}金，每小时训练可以获得${multiplier}次战斗的标准经验值`;

      // 等级上限提示（未转上限100级，简化处理）
      if (level >= 100) {
        k = "2";
        v = "已达等级上限，无法进行训练";
      } else if (trainingRecord) {
        if (trainingRecord.isTraining) {
          // 正在训练中
          if (trainingRecord.trainingEndTime) {
            const now = new Date();
            if (now >= trainingRecord.trainingEndTime) {
              // 训练已完成，可以领取
              k = "3";
              const pend = Number((trainingRecord as any).pendingExp || 0);
              v = `领取训练经验${pend}`;
            } else {
              // 训练进行中
              const remainingMs = Math.max(
                0,
                trainingRecord.trainingEndTime.getTime() - now.getTime()
              );
              const remainingHours = Math.floor(remainingMs / (1000 * 60 * 60));
              const remainingMinutes = Math.ceil(
                (remainingMs % (1000 * 60 * 60)) / (1000 * 60)
              );
              k = "1";
              v = `训练进行中，还需${remainingHours}小时${remainingMinutes}分钟完成`;
            }
          } else {
            // 训练状态异常
            k = "2";
            v = "训练状态异常";
          }
        } else if (trainingRecord.trainingStatus === 2) {
          // 训练已完成但未领取
          k = "3";
          const pend = Number((trainingRecord as any).pendingExp || 0);
          v = `领取训练经验${pend}`;
        }
      }

      return {
        act_id: 1205,
        code: 0,
        data: {
          k: k,
          v: v,
        },
      };
    } catch (error: any) {
      this.logger.error(`获取训练详情失败: characterId=${characterId}`, error);
      return {
        act_id: 1205,
        code: -1,
        msg: error.message || "获取训练详情失败",
      };
    }
  }

  /**
   * 开始训练 (1207)
   */
  async startTraining(characterId: number, hours: number): Promise<any> {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // 验证参数
      if (!hours || hours <= 0 || hours > 10) {
        return {
          act_id: 1207,
          code: -1,
          msg: "训练时间必须在1-10小时之间",
        };
      }

      // 获取角色信息
      const character = await queryRunner.manager.findOne(CharacterEntity, {
        where: { id: characterId },
      });

      if (!character) {
        return {
          act_id: 1207,
          code: -1,
          msg: "角色不存在",
        };
      }

      // 等级上限校验（未转简化为100级上限）
      const levelCap =
        (character.trans || 0) <= 0
          ? 100
          : character.trans === 1
          ? 120
          : character.trans === 2
          ? 140
          : 160;
      if (character.lvl >= levelCap) {
        return {
          act_id: 1207,
          code: -1,
          msg: "已达等级上限，无法进行训练",
        };
      }

      // 获取角色资源
      const resources = await queryRunner.manager.findOne(
        CharacterResourcesEntity,
        {
          where: { characterId },
        }
      );

      if (!resources) {
        return {
          act_id: 1207,
          code: -1,
          msg: "角色资源不存在",
        };
      }

      // 计算训练费用
      const level = character.lvl;
      const costPerHour = this.calculateTrainingCost(level);
      const totalCost = costPerHour * hours;

      // 检查金币是否足够
      if (resources.gold < totalCost) {
        return {
          act_id: 1207,
          code: 8,
          msg: `您的金数量不足${totalCost}金,`,
        };
      }

      // 体力值消耗规则：20 * 训练小时数
      const staminaCost = Math.max(0, Math.floor(hours)) * 20;
      if (staminaCost > 0) {
        try {
          await this.characterService.decreaseSinew(characterId, staminaCost, {
            queryRunner,
          });
        } catch (e: any) {
          await queryRunner.rollbackTransaction();
          return {
            act_id: 1207,
            code: -1,
            msg: e?.message || `体力不足，需要${staminaCost}点体力值`,
          };
        }
      }

      // 获取或创建训练记录
      let trainingRecord = await queryRunner.manager.findOne(
        CharacterTrainingEntity,
        {
          where: { characterId },
        }
      );

      // 每日一次校验：如果今天已有训练记录（依据 lastTrainingTime 或 start/end 时间），则禁止
      if (trainingRecord) {
        const today = new Date();
        const refTime =
          (trainingRecord as any).lastTrainingTime ||
          (trainingRecord as any).trainingEndTime ||
          (trainingRecord as any).trainingStartTime;
        if (refTime) {
          const ref = new Date(refTime);
          const sameDay =
            ref.getFullYear() === today.getFullYear() &&
            ref.getMonth() === today.getMonth() &&
            ref.getDate() === today.getDate();
          if (sameDay) {
            await queryRunner.rollbackTransaction();
            return {
              act_id: 1207,
              code: -1,
              msg: "每天只能训练一次，已达到今日训练次数",
            };
          }
        }
      }

      if (!trainingRecord) {
        trainingRecord = queryRunner.manager.create(CharacterTrainingEntity, {
          characterId,
          trainingHours: 0,
          totalTrainingHours: 0,
          isTraining: false,
        });
      }

      // 检查是否已经在训练中
      if (trainingRecord.isTraining) {
        return {
          act_id: 1207,
          code: -1,
          msg: "您已经在训练中，请等待当前训练完成",
        };
      }

      // 扣除金币
      await queryRunner.manager.update(
        CharacterResourcesEntity,
        { characterId },
        { gold: resources.gold - totalCost }
      );

      // 计算获得的经验值（仅记录，不直接结算，等待1208领取）
      const expGained = await this.computeTrainingExp(level, hours);

      // 设置训练为进行中，按时长计算结束时间
      const now = new Date();
      const end = new Date(now.getTime() + hours * 60 * 60 * 1000);

      // 获取或创建训练记录（进行中），仅记录可领取经验
      trainingRecord.isTraining = true;
      trainingRecord.trainingStatus = 1; // 1=进行中
      trainingRecord.trainingStartTime = now;
      trainingRecord.trainingEndTime = end;
      trainingRecord.trainingHours = hours;
      trainingRecord.totalTrainingHours += hours;
      trainingRecord.lastTrainingTime = now;
      trainingRecord.pendingExp = expGained; // 记录训练所得经验，供1208领取

      await queryRunner.manager.save(trainingRecord);

      await queryRunner.commitTransaction();

      const message = `训练已开始，预计${hours}小时后可领取${expGained}经验值`;
      return {
        act_id: 1207,
        code: 0,
        msg: message,
        data: message,
      };
    } catch (error: any) {
      await queryRunner.rollbackTransaction();
      this.logger.error(
        `开始训练失败: characterId=${characterId}, hours=${hours}`,
        error
      );
      return {
        act_id: 1207,
        code: -1,
        msg: error.message || "开始训练失败",
      };
    } finally {
      await queryRunner.release();
    }
  }

  /**
   * 完成训练
   * 计算并给予经验值
   */
  async completeTraining(characterId: number): Promise<any> {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      const trainingRecord = await queryRunner.manager.findOne(
        CharacterTrainingEntity,
        {
          where: { characterId, isTraining: true },
        }
      );

      if (!trainingRecord) {
        return {
          success: false,
          msg: "没有正在进行的训练",
        };
      }

      // 检查训练是否完成
      const now = new Date();
      if (
        trainingRecord.trainingEndTime &&
        now < trainingRecord.trainingEndTime
      ) {
        return {
          success: false,
          msg: "训练尚未完成",
        };
      }

      // 获取角色信息
      const character = await queryRunner.manager.findOne(CharacterEntity, {
        where: { id: characterId },
      });

      if (!character) {
        return {
          success: false,
          msg: "角色不存在",
        };
      }

      // 计算获得的经验值
      const level = character.lvl;
      const multiplier = this.getTrainingMultiplier(level);
      const baseExp = 100; // 基础经验值
      const expGained = baseExp * multiplier * trainingRecord.trainingHours;

      // 更新角色经验（exp字段代表升级还需要多少经验，训练应该减少这个值）
      let newExp = character.exp - expGained;
      let newLevel = character.lvl;
      let leveledUp = false;

      // 检查是否升级
      if (newExp <= 0) {
        leveledUp = true;
        newLevel = character.lvl + 1;
        // 计算下一级所需经验（这里使用简单的公式，可以根据需要调整）
        newExp = newLevel * 1000; // 下一级所需经验
      }

      await queryRunner.manager.update(
        CharacterEntity,
        { id: characterId },
        {
          exp: newExp,
          lvl: newLevel,
        }
      );

      // 如果升级了，处理属性点增加并推送系统消息
      if (leveledUp) {
        try {
          await this.characterAttributeService.handleLevelUp(
            characterId,
            newLevel
          );
          this.logger.log(
            `角色 ${characterId} 升级到 ${newLevel} 级，属性点已更新`
          );

          // 推送系统个人消息（1033可拉取）
          try {
            const nowTime = new Date();
            const dateStr = nowTime.toLocaleTimeString("zh-CN", {
              hour12: false,
              hour: "2-digit",
              minute: "2-digit",
              second: "2-digit",
            });
            const personalMessageBody = {
              content: `恭喜您升到${newLevel}级!获得520银两奖励.`,
              date: dateStr,
              fname: "系统信息",
            };
            await this.systemMessageService.savePersonalMessage(
              personalMessageBody,
              characterId,
              1000,
              "系统"
            );
          } catch (e: any) {
            this.logger.warn(`发送升级系统消息失败: ${e?.message || e}`);
          }
        } catch (error: any) {
          this.logger.error(`处理角色 ${characterId} 升级属性点失败:`, error);
          // 不抛出错误，继续执行训练完成逻辑
        }
      }

      // 更新训练记录
      trainingRecord.isTraining = false;
      trainingRecord.trainingStatus = 2; // 设置为已完成状态
      trainingRecord.trainingStartTime = undefined;
      trainingRecord.trainingEndTime = undefined;
      trainingRecord.trainingHours = 0;

      await queryRunner.manager.save(trainingRecord);

      await queryRunner.commitTransaction();

      let message = `训练完成，获得${expGained}经验值`;
      if (leveledUp) {
        message += `，恭喜升级到${newLevel}级！`;
      }

      return {
        success: true,
        msg: message,
        expGained,
        newExp,
        newLevel,
        leveledUp,
      };
    } catch (error: any) {
      await queryRunner.rollbackTransaction();
      this.logger.error(`完成训练失败: characterId=${characterId}`, error);
      return {
        success: false,
        msg: error.message || "完成训练失败",
      };
    } finally {
      await queryRunner.release();
    }
  }

  /**
   * 领取训练奖励 (1208)
   */
  async claimTrainingReward(characterId: number): Promise<any> {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      // 1. 检查角色是否存在
      const character = await queryRunner.manager.findOne(CharacterEntity, {
        where: { id: characterId },
      });

      if (!character) {
        return {
          act_id: 1208,
          code: -1,
          msg: "角色不存在",
        };
      }

      // 2. 获取训练记录
      const trainingRecord = await queryRunner.manager.findOne(
        CharacterTrainingEntity,
        {
          where: { characterId },
        }
      );

      if (!trainingRecord) {
        return {
          act_id: 1208,
          code: -1,
          msg: "没有训练记录",
        };
      }

      // 3. 检查训练状态
      if (!trainingRecord.isTraining && trainingRecord.trainingStatus !== 2) {
        return {
          act_id: 1208,
          code: -1,
          msg: "没有可领取的训练奖励",
        };
      }

      // 4. 检查训练是否已完成
      if (trainingRecord.isTraining && trainingRecord.trainingEndTime) {
        const now = new Date();
        if (now < trainingRecord.trainingEndTime) {
          return {
            act_id: 1208,
            code: -1,
            msg: "训练尚未完成",
          };
        }
      }

      // 5. 计算奖励
      // 使用1207阶段预存的 pendingExp（可能为bigint/字符串，统一数值化），不回退重算
      const expGainedRaw = (trainingRecord as any).pendingExp;
      const expGained = expGainedRaw != null ? Number(expGainedRaw) : 0;
      if (!expGained || expGained <= 0) {
        return {
          act_id: 1208,
          code: -1,
          msg: "没有可领取的训练奖励",
        };
      }

      // 6. 使用通用经验结算（包含等级上限与溢出）
      const applyResult = await this.characterService.applyExperience(
        characterId,
        expGained,
        { queryRunner }
      );
      const newLevel = applyResult.newLevel;
      const newExp = applyResult.newExp;
      const leveledUp = applyResult.levelUpTimes > 0;

      character.lvl = newLevel;
      character.exp = newExp;
      await queryRunner.manager.save(character);

      // 7. 更新训练记录状态
      trainingRecord.isTraining = false;
      trainingRecord.trainingStatus = 0; // 重置为未训练状态
      trainingRecord.trainingStartTime = undefined;
      trainingRecord.trainingEndTime = undefined;
      trainingRecord.trainingHours = 0;
      // 领取后清零pendingExp，重置状态
      trainingRecord.pendingExp = 0;
      await queryRunner.manager.save(trainingRecord);

      // 8. 如果升级了，只发送一次系统个人消息（以最终等级为准）
      if (leveledUp) {
        try {
          const nowTime = new Date();
          const dateStr = nowTime.toLocaleTimeString("zh-CN", {
            hour12: false,
            hour: "2-digit",
            minute: "2-digit",
            second: "2-digit",
          });
          const personalMessageBody = {
            content: `恭喜您升到${newLevel}级!获得520银两奖励.`,
            date: dateStr,
            fname: "系统信息",
          };
          await this.systemMessageService.savePersonalMessage(
            personalMessageBody,
            characterId,
            1000,
            "系统"
          );
        } catch (error: any) {
          this.logger.warn(`发送升级系统消息失败: ${error?.message || error}`);
        }
      }

      await queryRunner.commitTransaction();

      let message = `训练奖励领取成功，获得${expGained}经验值`;
      if (leveledUp) {
        message += `，恭喜升级到${newLevel}级！`;
      }

      return {
        act_id: 1208,
        code: 0,
        data: message,
      };
    } catch (error: any) {
      await queryRunner.rollbackTransaction();
      this.logger.error(`领取训练奖励失败: characterId=${characterId}`, error);
      return {
        act_id: 1208,
        code: -1,
        msg: error.message || "领取训练奖励失败",
      };
    } finally {
      await queryRunner.release();
    }
  }

  /**
   * 获取训练状态
   */
  async getTrainingStatus(characterId: number): Promise<any> {
    try {
      const trainingRecord = await this.characterTrainingRepository.findOne({
        where: { characterId },
      });

      if (!trainingRecord) {
        return {
          isTraining: false,
          remainingTime: 0,
        };
      }

      if (!trainingRecord.isTraining || !trainingRecord.trainingEndTime) {
        return {
          isTraining: false,
          remainingTime: 0,
        };
      }

      const now = new Date();
      const remainingTime = Math.max(
        0,
        trainingRecord.trainingEndTime.getTime() - now.getTime()
      );

      return {
        isTraining: trainingRecord.isTraining,
        remainingTime: Math.floor(remainingTime / 1000), // 返回秒数
        endTime: trainingRecord.trainingEndTime,
      };
    } catch (error: any) {
      this.logger.error(`获取训练状态失败: characterId=${characterId}`, error);
      return {
        isTraining: false,
        remainingTime: 0,
      };
    }
  }
}
